package com.google.code.androiddatasender;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;

import com.google.code.androiddatasender.Msg.PacketInfo;

public class Receiver extends Thread implements Context {

	private Socket sck = null;
	private DataInputStream dis = null;
	private ReceiveCallback callback = null;
	private boolean running = true;
	private DataOutputStream dos = null;

	public Receiver(Socket sck, ReceiveCallback callback) {
		
		this.sck = sck;
		this.callback = callback;
		try {
			dos = new DataOutputStream(sck.getOutputStream());
			dis = new DataInputStream(sck.getInputStream());
		} catch (IOException e) {
		}
	}

	public void run() {
        byte[] large = new byte[65535*100];
		byte[] buffer = new byte[65535*2];
        int currSize = 0;
        int desiredSize = 0;
        int count = 0;
               
		Msg msg = new Msg();
		while (running) {
			try {
				int sz = dis.read(buffer, 0, buffer.length);
				
				if (sz > 0) {					
                    Msg.PacketInfo info = msg.new PacketInfo();
					info.fromByteArray(buffer);

					if (info.magic == Msg.PacketInfo.MAGIC && count == 0) {
						desiredSize = info.size;
						count = info.size + PacketInfo.MAX_LENGTH;
					} else {
						count -= sz;
					}
					
					if (desiredSize <= currSize + sz) {
						System.arraycopy(buffer, 0, large, currSize, sz);
						currSize += sz;
						
						while (desiredSize <= currSize) {
							
							byte[] payload = new byte[desiredSize + PacketInfo.MAX_LENGTH];
							System.arraycopy(large, 0, payload, 0, desiredSize + PacketInfo.MAX_LENGTH);
							msg.fromByteArray(payload);
							callback.onReceive(this, msg);
							
	                        if (desiredSize < currSize)
	                        {
	                            System.arraycopy(large, desiredSize + Msg.PacketInfo.MAX_LENGTH, buffer, 0, currSize - desiredSize + Msg.PacketInfo.MAX_LENGTH);
	                            System.arraycopy(buffer, 0, large, 0, currSize - desiredSize + Msg.PacketInfo.MAX_LENGTH);
	                            currSize = currSize - desiredSize - Msg.PacketInfo.MAX_LENGTH;
	                    
	        					info.fromByteArray(buffer);	        					
	        					if (info.magic == Msg.PacketInfo.MAGIC) {
	        						desiredSize = info.size;
	        						count = info.size + PacketInfo.MAX_LENGTH;
	        					}
	        					
	                        }
						}
						count = 0;
						
                    }
                    else
                    {
                        System.arraycopy(buffer, 0, large, currSize, sz);
                        currSize += sz;
                    }
				} else {
					running = false;
				}
			} catch (IOException ioe) {
			}
		}
	}

	public void send(Msg msg) { // send 1 : 1 connection
		try {
            byte[] buffer = msg.packet.toByteArray();           
            dos.write(buffer, 0, buffer.length);
            dos.flush();
        } catch (IOException e) {
        }
	}
	
	public void shutdown() {
		this.running = false;
		try {
			sck.close();
		} catch (IOException ioe) {
		}
	}

}
